﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Percolation.Gui
{
    public partial class EditRangeForm : Form
    {
        public NetRangeSettings RangeSettings { get; private set; }

        public EditRangeForm(NetRangeSettings rangeSettings)
        {
            RangeSettings = Extensions.DeepCopy(rangeSettings);
            InitializeComponent();
            InitializeTypeComboBox();
        }

        private void InitializeTypeComboBox()
        {
            m_typeComboBox.Items.Clear();
            foreach (RangeTypeEnum rangeType in System.Enum.GetValues(typeof(RangeTypeEnum)))
                m_typeComboBox.Items.Add(EnumUtils.GetString(rangeType));

            m_typeComboBox.SelectedIndex = (int)RangeSettings.Type;
        }

        private void updatePackList()
        {
            m_packsListBox.Items.Clear();

            if (RangeSettings.Type == RangeTypeEnum.CustomRange)
            {
                foreach (NetPackSettings packSettings in RangeSettings.PackSettingsList)
                    m_packsListBox.Items.Add(packSettings.GetDescription());
            }
            else
            {
                foreach (double d in RangeSettings.ProbabilityList)
                    m_packsListBox.Items.Add("Average probability " + d.ToString());
            }
        }

        private void updatePage()
        {
            m_widthTextBox.Text = RangeSettings.NetWidth.ToString();
            m_heightTextBox.Text = RangeSettings.NetHeight.ToString();

            if (RangeSettings.Type != RangeTypeEnum.CustomRange)
                m_packExperimentsTextBox.Text = RangeSettings.PackExperiments.ToString();
            else
                m_packExperimentsTextBox.Text = "10";

            if (RangeSettings.Type == RangeTypeEnum.HorGradientRange || RangeSettings.Type == RangeTypeEnum.VerGradientRange)
                m_gradProbabilityTextBox.Text = RangeSettings.GradProbability.ToString();
            else
                m_gradProbabilityTextBox.Text = "0.5";

            updatePackList();
        }

        private void updateAccessibleState(bool packExperimentsField, bool gradProbabilityField)
        {
            m_packExperimentsLabel.Visible = packExperimentsField;
            m_packExperimentsTextBox.Visible = packExperimentsField;

            m_gradProbabilityLabel.Visible = gradProbabilityField;
            m_gradProbabilityTextBox.Visible = gradProbabilityField;

            updatePackList();
        }

        private void m_typeComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            RangeSettings.Type = (RangeTypeEnum)m_typeComboBox.SelectedIndex;
            
            if (m_typeComboBox.SelectedIndex == 0)
                updateAccessibleState(true, false);
            else if (m_typeComboBox.SelectedIndex == 1 || m_typeComboBox.SelectedIndex == 2)
                updateAccessibleState(true, true);
            else if (m_typeComboBox.SelectedIndex == 3)
                updateAccessibleState(false, false);
        }

        private void updateProperties()
        {
            RangeSettings.NetWidth = System.Convert.ToInt32(m_widthTextBox.Text);
            RangeSettings.NetHeight = System.Convert.ToInt32(m_heightTextBox.Text);

            if (RangeSettings.Type != RangeTypeEnum.CustomRange)
                RangeSettings.PackExperiments = System.Convert.ToInt32(m_packExperimentsTextBox.Text);

            if (RangeSettings.Type == RangeTypeEnum.HorGradientRange || RangeSettings.Type == RangeTypeEnum.VerGradientRange)
                RangeSettings.GradProbability = System.Convert.ToDouble(m_gradProbabilityTextBox.Text);
        }

        private bool isValidSize(int size)
        {
            return (10 <= size && size <= 150);
        }

        private bool isValidExpCount(int expCount)
        {
            return (1 <= expCount && expCount <= 1000);
        }

        private bool isValidProbability(double probability)
        {
            return (0 <= probability && probability <= 1.0);
        }

        private bool isValidGradProbability(double gradProbability, double probability)
        {
            return isValidProbability(probability - probability * gradProbability) && isValidProbability(probability + probability * gradProbability);
        }

        private bool validateWidth()
        {
            try
            {
                int width = System.Convert.ToInt32(m_widthTextBox.Text);
                if (isValidSize(width))
                {
                    m_errorProvider.SetError(m_widthTextBox, "");
                    return true;
                }

                m_errorProvider.SetError(m_widthTextBox, "Width value is invalid (should be greater or equal than 10 and less or equal than 150)");
                return false;
            }
            catch (Exception)
            {
                m_errorProvider.SetError(m_widthTextBox, "You entered some non-digit symbols");
                return false;
            }
        }

        private bool validateHeight()
        {
            try
            {
                int height = System.Convert.ToInt32(m_heightTextBox.Text);
                if (isValidSize(height))
                {
                    m_errorProvider.SetError(m_heightTextBox, "");
                    return true;
                }

                m_errorProvider.SetError(m_heightTextBox, "Height value is invalid (should be greater or equal than 10 and less or equal than 150)");
                return false;
            }
            catch (Exception)
            {
                m_errorProvider.SetError(m_heightTextBox, "You entered some non-digit symbols");
                return false;
            }
        }

        private bool validateWidthHeight()
        {
            if (validateHeight() && validateWidth())
            {
                int width = System.Convert.ToInt32(m_widthTextBox.Text);
                int height = System.Convert.ToInt32(m_heightTextBox.Text);

                if (width == height)
                {
                    m_errorProvider.SetError(m_widthTextBox, "");
                    m_errorProvider.SetError(m_heightTextBox, "");
                    return true;
                }
                else
                {
                    m_errorProvider.SetError(m_widthTextBox, "Width and height values should be equal");
                    m_errorProvider.SetError(m_heightTextBox, "Width and height values should be equal");
                    return false;
                }
            }

            return false;
        }

        private bool validateExpCount()
        {
            if (m_packExperimentsTextBox.Visible == false)
                return true;

            try
            {
                int expCount = System.Convert.ToInt32(m_packExperimentsTextBox.Text);
                if (isValidExpCount(expCount))
                {
                    m_errorProvider.SetError(m_packExperimentsTextBox, "");
                    return true;
                }

                m_errorProvider.SetError(m_packExperimentsTextBox, "Experiments count value is invalid (should be greater or equal than 1 and less or equal than 1000)");
                return false;
            }
            catch (Exception)
            {
                m_errorProvider.SetError(m_packExperimentsTextBox, "You entered some non-digit symbols");
                return false;
            }
        }

        private bool validateGradProbability()
        {
            if (m_gradProbabilityTextBox.Visible == false)
                return true;

            try
            {
                double maxProbability = RangeSettings.ProbabilityList.Max();
                double gradProbability = System.Convert.ToDouble(m_gradProbabilityTextBox.Text);
                if (isValidGradProbability(gradProbability, maxProbability))
                {
                    m_errorProvider.SetError(m_gradProbabilityTextBox, "");
                    return true;
                }

                m_errorProvider.SetError(m_gradProbabilityTextBox, "Gradient probability value is invalid with this some values of average probability");
                return false;
            }
            catch (Exception e)
            {
                m_errorProvider.SetError(m_gradProbabilityTextBox, "You entered some non-digit symbols");
                return false;
            }
        }

        private bool validateList()
        {
            if (m_packsListBox.Items.Count > 0)
            {
                m_errorProvider.SetError(m_packsListBox, "");
                return true;
            }

            m_errorProvider.SetError(m_packsListBox, "No items in list");
            return false;
        }

        private bool validateForm()
        {
            bool valid = true;
            valid &= validateWidthHeight();
            valid &= validateExpCount();
            valid &= validateList();
            valid &= validateGradProbability();
            return valid;
        }

        private void m_okButton_Click(object sender, EventArgs e)
        {
            if (!validateForm())
                return;

            updateProperties();
            DialogResult = System.Windows.Forms.DialogResult.OK;
            Close();
        }

        private void m_cancelButton_Click(object sender, EventArgs e)
        {
            DialogResult = System.Windows.Forms.DialogResult.Cancel;
            Close();
        }

        private void EditRangeForm_Load(object sender, EventArgs e)
        {
            updatePage();
        }

        private void m_addButton_Click(object sender, EventArgs e)
        {
            if (m_typeComboBox.SelectedIndex == (int) RangeTypeEnum.CustomRange)
            {
                if (!validateWidth())
                    return;

                NetPackSettings packSettings = new NetPackSettings();
                packSettings.Width = System.Convert.ToInt32(m_widthTextBox.Text);
                packSettings.Height = packSettings.Width;
                EditPackForm dialog = new EditPackForm(packSettings);
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    RangeSettings.PackSettingsList.Add(packSettings);
                    updatePackList();
                }
            }
            else
            {
                EditProbabilityForm dialog = new EditProbabilityForm(0.5);
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    RangeSettings.ProbabilityList.Add(dialog.Probability);
                    updatePackList();
                }
            }
        }

        private void m_editButton_Click(object sender, EventArgs e)
        {
            if (m_packsListBox.SelectedIndex == -1)
                return;

            if (m_typeComboBox.SelectedIndex == (int) RangeTypeEnum.CustomRange)
            {
                NetPackSettings packSettings = RangeSettings.PackSettingsList[m_packsListBox.SelectedIndex];
                EditPackForm dialog = new EditPackForm(packSettings);
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    RangeSettings.PackSettingsList[m_packsListBox.SelectedIndex] = packSettings;
                    updatePackList();
                }
            }
            else
            {
                EditProbabilityForm dialog = new EditProbabilityForm(RangeSettings.ProbabilityList[m_packsListBox.SelectedIndex]);
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    RangeSettings.ProbabilityList[m_packsListBox.SelectedIndex] = dialog.Probability;
                    updatePackList();
                }
            }
        }

        private void m_removeButton_Click(object sender, EventArgs e)
        {
            if (m_packsListBox.SelectedIndex == -1)
                return;

            if (MessageBox.Show("Delete selected pack?", "Percolation", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
            {
                if (m_typeComboBox.SelectedIndex == (int)RangeTypeEnum.CustomRange)
                    RangeSettings.PackSettingsList.RemoveAt(m_packsListBox.SelectedIndex);
                else
                    RangeSettings.ProbabilityList.RemoveAt(m_packsListBox.SelectedIndex);

                updatePackList();
            }
        }
    }
}
